#include <Arduino.h>
#include <Ticker.h>
#include <OneButton.h>

#include "src/my_u8g2.h"
#include "src/sensors.h"
#include "src/config.h"
#include "src/led.h"
#include "src/persistence.h"
#include "src/ptime.h"
#include "src/plog.h"
#include "src/pwifi.h"
#include "src/web_server.h"
#include "src/application.h"

#define SW_BUTTON_PIN 21

OneButton sw_btn(SW_BUTTON_PIN, true);
Ticker my_ticker_1s;
static bool ticker_1s_flag = true; // 第一次进入
static bool ticker_min_flag = false;

void setup()
{
  Serial.begin(115200);

  // iic 统一设置pin
  Wire.setPins(I2C_SDA_PIN, I2C_SCL_PIN); // 统一设置底层wire
  U8G2_init();
  U8G2_welcome();

  delay(1000); // note！否则无法打印log
  log_set_level(LOG_LEVEL_DEBUG);

  LED_init();
  sw_btn_init();
  P_LittleFS.init();

  GS_init(); // note：只初始化，不启动
#ifdef ES_ENABLE
  ES_init();
#endif
  // wifi
  if (need_init_sys_config())
  {
    LOG_INFO("need sync sys_config from wifi");
    App_init_sys_config();
  }

#ifdef WEB_SERVER_DEFAULT_ON // 是否默认开启，而不是外部按键触发
  web_server_start();
#endif

  my_ticker_1s.attach(1, ticker_cb_1s);
  Serial.println("=======================  PAqm start!  =======================");

#ifdef U8G2_SLEEP_ENABLE
  U8G2_refresh_active_time();
#endif
}

Sensor_result_t res;
void loop()
{
  if (ticker_1s_flag) // 1s
  {
    ticker_1s_flag = false;
    LOG_DEBUG("loop 1s");

    if (ticker_min_flag)
    {
      ticker_min_flag = false;
      LOG_DEBUG("loop min");

      GS_start();
      wait_until_data_stable(); // 这里可能会有些耗时（最多也就15s），但是不影响定时获取数据的周期，该周期不会相差太大（因为用的是定时器而不是loop中delay）

      // 读取n次数据，取平均值，又会耗时n s，不过间隔长问题不大
      Sensor_result_t res_avg = {};
      for (int i = 0; i < SENSOR_READ_AVG_NUM; i++)
      {
        Sensor_result_t res_tmp = Sensor_collect_once();
        res_avg.gs.eco2 += res_tmp.gs.eco2;
        res_avg.gs.tvoc += res_tmp.gs.tvoc;
        res_avg.es.temperature += res_tmp.es.temperature;
        res_avg.es.humidity += res_tmp.es.humidity;
        res_avg.es.pressure += res_tmp.es.pressure;
        delay(1000); // 按照芯片手册要求，每s读取一次数据
      }

      res_avg.gs.eco2 /= uint16_t(SENSOR_READ_AVG_NUM);
      res_avg.gs.tvoc /= uint16_t(SENSOR_READ_AVG_NUM);
      res_avg.es.temperature /= float(SENSOR_READ_AVG_NUM);
      res_avg.es.humidity /= float(SENSOR_READ_AVG_NUM);
      res_avg.es.pressure /= float(SENSOR_READ_AVG_NUM);

      res = res_avg;
      App_sensor_persistent(&res);

      // LED_blinker_blink();

      GS_stop();
    }

    App_mode_loop(&res);

    LED_blinker_toggle();
#ifdef U8G2_SLEEP_ENABLE
    U8G2_sleep_check();
#endif
  }

  // 如果使用了非异步web_server, 则需要在loop中调用，但是这种情况只能是默认开启 todo
  // web_server_loop();

  sw_btn.tick();
  delay(1);
}

void sw_btn_init()
{
  pinMode(SW_BUTTON_PIN, INPUT);

  sw_btn.reset();
  sw_btn.setPressMs(3000); // ms 按住按钮以触发长按的持续时间。

  sw_btn.attachPress(sw_btn_press);
  sw_btn.attachClick(sw_btn_click);
  sw_btn.attachDoubleClick(sw_btn_double_click);
  sw_btn.attachMultiClick(sw_btn_multi_click);
  sw_btn.attachLongPressStart(sw_btn_long_click);
  // sw_btn.attachDuringLongPress(sw_btn_during_long_click);
  // sw_btn.attachLongPressStop(sw_btn_long_click_stop);
}

// 类似于按键中断，任何行为都会触发
void sw_btn_press()
{
  LOG_INFO("sw_btn_press");
#ifdef U8G2_SLEEP_ENABLE
  U8G2_refresh_active_time();
  U8G2_wakeup();
#endif
}

void sw_btn_click()
{
  LOG_DEBUG("sw_btn_click");
  App_mode_next();
}

void sw_btn_double_click()
{
  LOG_DEBUG("sw_btn_double_click");
#ifndef WEB_SERVER_DEFAULT_ON
  App_mode_set(MODE_WEB_SERVER);
#endif
}

void sw_btn_multi_click()
{
  int num = sw_btn.getNumberClicks();
  LOG_DEBUG("sw_btn_multi_click, num %d", num);
  if (num == 3)
  {
    App_mode_set(MODE_SYS_CONFIG);
  }
}

void sw_btn_long_click()
{
  LOG_DEBUG("sw_btn_long_click");
  // 方案1. 清除指定内容
  P_LittleFS.formatFS();
  pwifi_sta_reset();
  delay(1000);
  ESP.restart();
  // 方案2. 暴力擦除所有flash!
  // 不能删除 littlefs，可以查看源码,nvs不能删除
  // pwifi_flash_erase();
}

uint32_t ticker_1s_cnt = 0;
void ticker_cb_1s()
{
  ticker_1s_flag = true;
  ticker_1s_cnt++;
  if (ticker_1s_cnt == PERSISTENCE_PERIOD)
  {
    ticker_min_flag = true;
    ticker_1s_cnt = 0;
  }
}
